home *** CD-ROM | disk | FTP | other *** search
/ Amiga Plus Special 26 / AMIGAplus Sonderheft 26 (2000)(Falke)(DE)(Track 1 of 2)[!].iso / Tools / GFX-Viewer / Animviewer / mpegvideo_datatype / dispatch.c < prev    next >
C/C++ Source or Header  |  1999-03-29  |  79KB  |  2,366 lines

  1.  
  2. /*
  3. **
  4. **  $VER: dispatch.c 1.11 (7.11.97)
  5. **  mpegvideo.datatype 1.11
  6. **
  7. **  Dispatch routine for a DataTypes class
  8. **
  9. **  Written 1996/1997 by Roland 'Gizzy' Mainz
  10. **  Original example source from David N. Junod
  11. **
  12. */
  13.  
  14. /* main includes */
  15. #include "classbase.h"
  16.  
  17. /* ansi includes */
  18. #include <limits.h>
  19.  
  20. /* project includes */
  21. #include "mpegutil.h"
  22.  
  23. /*****************************************************************************/
  24.  
  25. /* is animation.datatype V41 ? */
  26. #define ISV41 ((classbase -> cb_SuperClassBase -> lib_Version) == 41U)
  27.  
  28. /*****************************************************************************/
  29.  
  30. /* local prototypes */
  31. static LONG              LoadFrames( struct ClassBase *, Object * );
  32. static STRPTR            GetPrefsVar( struct ClassBase *, STRPTR );
  33. static BOOL              matchstr( struct ClassBase *, STRPTR, STRPTR );
  34. static void              ReadENVPrefs( struct ClassBase *, struct MPEGVideoInstData * );
  35. static void              OpenLogfile( struct ClassBase *, struct MPEGVideoInstData * );
  36. static BOOL              AttemptOpenVMM( struct MPEGVideoInstData * );
  37. static void              AttachSample( struct MPEGVideoInstData * );
  38.  
  39. static void              CreateProgressRequester( struct MPEGVideoInstData * );
  40. static void              DeleteProgressRequester( struct MPEGVideoInstData * );
  41.  
  42. static struct FrameNode *FindNextIFrame( struct FrameNode * );
  43.  
  44. static struct BitMap    *AllocFastBitMap( struct MPEGVideoInstData *, ULONG, ULONG, ULONG );
  45. static void              CopyBitMap( struct ClassBase *, struct BitMap *, struct BitMap *, ULONG, ULONG );
  46.  
  47.  
  48. /*****************************************************************************/
  49.  
  50.  
  51. struct IClass *initClass( struct ClassBase *classbase )
  52. {
  53.     struct IClass *cl;
  54.  
  55.     init_tables();
  56.  
  57.     /* Create our class... */
  58.     if( cl = MakeClass( MPEGVIDEODTCLASS, ANIMATIONDTCLASS, NULL, (ULONG)sizeof( struct MPEGVideoInstData ), 0UL ) )
  59.     {
  60. #define DTSTACKSIZE (16384UL)
  61.       cl -> cl_Dispatcher . h_Entry    = (HOOKFUNC)StackSwapDispatch; /* see stackswap.c */
  62.       cl -> cl_Dispatcher . h_SubEntry = (HOOKFUNC)Dispatch;
  63.       cl -> cl_Dispatcher . h_Data     = (APTR)DTSTACKSIZE;           /* see stackswap.c */
  64.       cl -> cl_UserData                = (ULONG)classbase;
  65.  
  66.       AddClass( cl );
  67.     }
  68.  
  69.     return( cl );
  70. }
  71.  
  72. /*****************************************************************************/
  73.  
  74.  
  75. /* class dispatcher */
  76. DISPATCHERFLAGS
  77. ULONG Dispatch( REGA0 struct IClass *cl, REGA2 Object *o, REGA1 Msg msg )
  78. {
  79.     struct ClassBase          *classbase = (struct ClassBase *)(cl -> cl_UserData);
  80.     struct MPEGVideoInstData  *mvid;
  81.     ULONG                      retval    = 0UL;
  82.  
  83.     switch( msg -> MethodID )
  84.     {
  85. /****** mpegvideo.datatype/OM_NEW *********************************************
  86. *
  87. *    NAME
  88. *        OM_NEW -- Create a mpegvideo.datatype object.
  89. *
  90. *    FUNCTION
  91. *        The OM_NEW method is used to create an instance of the
  92. *        mpegvideo.datatype class.  This method is passed to the superclass
  93. *        first. After this, mpegvideo.datatype loads it's preference file
  94. *        (and the sound file, if one was specified), parses the whole video
  95. *        stream, putting pictures into memory.
  96. *        Any fatal error aborts the load, non-serious errors are reported.
  97. *
  98. *        Subclasses of mpegvideo.datatype are not supported. Any attempt to
  99. *        create a subclass object of mpegvideo.datatype will be rejected
  100. *        by this method.
  101. *
  102. *    ATTRIBUTES
  103. *        The following attributes can be specified at creation time.
  104. *
  105. *        DTA_SourceType (ULONG) -- Determinates the type of DTA_Handle
  106. *            attribute. Currently, only a source type of DTST_FILE is
  107. *            supported. If any other type was set in a given DTA_SourceType,
  108. *            OM_NEW will be rejected with result2 == ERROR_OBJECT_WRONG_TYPE.
  109. *            Defaults to DTST_FILE.
  110. *
  111. *        DTA_Handle (BPTR) -- If DTA_SourceType is DTST_FILE, the given file
  112. *            handle will be used as an mpeg video stream to read in.
  113. *
  114. *    RESULT
  115. *        If the object was created a pointer to the object is returned,
  116. *        otherwise NULL is returned.
  117. *
  118. ******************************************************************************
  119. *
  120. */
  121.       case OM_NEW:
  122.       {
  123.           struct TagItem *ti;
  124.  
  125.           /* We only support DTST_FILE as DTA_SourceType type */
  126.           if( ti = FindTagItem( DTA_SourceType, (((struct opSet *)msg) -> ops_AttrList) ) )
  127.           {
  128.             if( (ti -> ti_Data) != DTST_FILE )
  129.             {
  130.               SetIoErr( ERROR_OBJECT_WRONG_TYPE );
  131.  
  132.               break;
  133.             }
  134.           }
  135.  
  136.           /* This must not be a subclass of mpegvideo.datatype
  137.            * (not implemented yet)
  138.            */
  139.           if( o == (Object *)cl )
  140.           {
  141.             if( retval = DoSuperMethodA( cl, o, msg ) )
  142.             {
  143.               LONG error;
  144.  
  145.               /* Load frames... */
  146.               if( error = LoadFrames( classbase, (Object *)retval ) )
  147.               {
  148.                 /* Something went fatally wrong, dispose object */
  149.                 CoerceMethod( cl, (Object *)retval, OM_DISPOSE );
  150.                 retval = 0UL;
  151.               }
  152.  
  153.               SetIoErr( error );
  154.             }
  155.           }
  156.           else
  157.           {
  158.             /* Subclasses of mpegvideo.datatype are not implemented */
  159.             SetIoErr( ERROR_NOT_IMPLEMENTED );
  160.           }
  161.       }
  162.           break;
  163.  
  164. /****** mpegvideo.datatype/OM_DISPOSE *****************************************
  165. *
  166. *    NAME
  167. *        OM_DISPOSE -- Delete a mpegvideo.datatype object.
  168. *
  169. *    FUNCTION
  170. *        The OM_DISPOSE method is used to delete an instance of the
  171. *        mpegvideo.datatype class.  This method is passed to the superclass
  172. *        when it has completed.
  173. *        This method frees all frame nodes and their contents (pictures, their
  174. *        colormaps, sounds etc.).
  175. *
  176. *    RESULT
  177. *        The object is deleted. 0UL is returned.
  178. *
  179. ******************************************************************************
  180. *
  181. */
  182.       case OM_DISPOSE:
  183.       {
  184.           struct FrameNode *fn;
  185.  
  186.           /* Get a pointer to our object data */
  187.           mvid = (struct MPEGVideoInstData *)INST_DATA( cl, o );
  188.  
  189.           if( (mvid -> mvid_LoadAll) == FALSE )
  190.           {
  191.             mpeg_closedown( mvid );
  192.           }
  193.  
  194.           /* Wait for any outstanding blitter usage (which may use one of our bitmaps) */
  195.           WaitBlit();
  196.  
  197.           /* Delete the frame list */
  198.           while( fn = (struct FrameNode *)RemHead( (struct List *)(&(mvid -> mvid_FrameList)) ) )
  199.           {
  200.             FreeFrameNode( mvid, fn );
  201.           }
  202.  
  203.           /* Free our key bitmap */
  204.           FreeBitMap( (mvid -> mvid_KeyBitMap) );
  205.  
  206.           /* Delete the frame pool */
  207.           DeletePool( (mvid -> mvid_Pool) );
  208.  
  209.           /* Close VERBOSE output file */
  210.           if( mvid -> mvid_VerboseOutput )
  211.           {
  212.             Close( (mvid -> mvid_VerboseOutput) );
  213.           }
  214.  
  215.           /* Dispose object */
  216.           DoSuperMethodA( cl, o, msg );
  217.       }
  218.           break;
  219.  
  220.       case OM_UPDATE:
  221.       {
  222.           if( DoMethod( o, ICM_CHECKLOOP ) )
  223.           {
  224.             break;
  225.           }
  226.       }
  227.       case OM_SET:
  228.       {
  229.           /* Pass the attributes to the animation class and force a refresh if we need it */
  230.           if( retval = DoSuperMethodA( cl, o, msg ) )
  231.           {
  232. /* The following statement is commented out because mpegvideo.datatype does not allow
  233.  * subclasses. Thus, the following statement is NOP unless subclasses are supported...
  234.  */
  235. #ifdef COMMENTED_OUT
  236.             /* Top instance ? */
  237.             if( OCLASS( o ) == cl )
  238. #endif /* COMMENTED_OUT */
  239.             {
  240.               struct RastPort *rp;
  241.  
  242.               /* Get a pointer to the rastport */
  243.               if( rp = ObtainGIRPort( (((struct opSet *)msg) -> ops_GInfo) ) )
  244.               {
  245.                 struct gpRender gpr;
  246.  
  247.                 /* Force a redraw */
  248.                 gpr . MethodID   = GM_RENDER;
  249.                 gpr . gpr_GInfo  = ((struct opSet *)msg) -> ops_GInfo;
  250.                 gpr . gpr_RPort  = rp;
  251.                 gpr . gpr_Redraw = GREDRAW_UPDATE;
  252.  
  253.                 DoMethodA( o, (Msg)(&gpr) );
  254.  
  255.                 /* Release the temporary rastport */
  256.                 ReleaseGIRPort( rp );
  257.  
  258.                 retval = 0UL;
  259.               }
  260.             }
  261.           }
  262.       }
  263.           break;
  264.  
  265. /****** mpevideo.datatype/DTM_WRITE ******************************************
  266. *
  267. *    NAME
  268. *        DTM_WRITE -- Save data
  269. *
  270. *    FUNCTION
  271. *        This method saves the object's contents to disk.
  272. *
  273. *        If dtw_Mode is DTWM_IFF, the method is passed unchanged to the
  274. *        superclass, animation.datatype, which writes a single IFF ILBM
  275. *        picture.
  276. *        The local data format (e.g. dtw_Mode == DTWM_RAW) is currently
  277. *        not supported, this method returns 0UL
  278. *        (and result2 == ERROR_NOT_IMPLEMENTED) in that case.
  279. *
  280. *    RESULT
  281. *        Returns 0 for failure (IoErr() returns result2), non-zero
  282. *        for success.
  283. *
  284. ******************************************************************************
  285. *
  286. */
  287.       case DTM_WRITE:
  288.       {
  289.           struct dtWrite *dtw;
  290.  
  291.           dtw = (struct dtWrite *)msg;
  292.  
  293.           /* Local data format not supported yet... */
  294.           if( (dtw -> dtw_Mode) == DTWM_RAW )
  295.           {
  296.             /* Return result = 0UL and result2 = ERROR_NOT_IMPLEMENTED */
  297.             SetIoErr( ERROR_NOT_IMPLEMENTED );
  298.           }
  299.           else
  300.           {
  301.             /* Pass msg to superclass (which writes a single frame as an IFF ILBM picture)... */
  302.             retval = DoSuperMethodA( cl, o, msg );
  303.           }
  304.       }
  305.           break;
  306.  
  307.  
  308. /****** mpegvideo.datatype/ADTM_LOADFRAME ************************************
  309. *
  310. *    NAME
  311. *        ADTM_LOADFRAME -- Load frame
  312. *
  313. *    FUNCTION
  314. *        The ADTM_LOADFRAME method is used to obtain the bitmap and timing
  315. *        data of the animation.
  316. *        The given timestamp will be used to find the closest timestamp
  317. *        in the internal FrameNode list. If it was found, the corresponding
  318. *        timing, bitmap, colormap and sound data are stored into the struct
  319. *        adtFrame.
  320. *
  321. *        The mpegvideo.datatype always loads a whole IPPB...I sequence
  322. *        into memory; the sequence stays in memory until all frames of
  323. *        the sequence are unloaded.
  324. *
  325. *    RESULT
  326. *        Returns non-zero if the frame was loaded, 0UL otherwise
  327. *        (Result2 (IoErr()) contains then the cause).
  328. *
  329. ******************************************************************************
  330. *
  331. */
  332.       case ADTM_LOADFRAME:
  333.       {
  334.           struct FrameNode *fn;
  335.           struct adtFrame  *alf;
  336.           LONG              error = 0L;
  337.  
  338.           mvid = (struct MPEGVideoInstData *)INST_DATA( cl, o );
  339.           alf = (struct adtFrame *)msg;
  340.  
  341.           /* Like "realloc": Free any given frame here */
  342.           if( alf -> alf_UserData )
  343.           {
  344.             msg -> MethodID = ADTM_UNLOADFRAME;
  345.  
  346.               DoMethodA( o, msg );
  347.  
  348.             msg -> MethodID = ADTM_LOADFRAME;
  349.           }
  350.  
  351.           /* Find frame by timestamp */
  352.           if( fn = FindFrameNode( (&(mvid -> mvid_FrameList)), (alf -> alf_TimeStamp) ) )
  353.           {
  354.             struct FrameNode *i_frame = ((fn -> fn_IFrame)?(fn -> fn_IFrame):(fn));
  355.  
  356.             /* Load bitmaps only if we don't cache the whole anim and
  357.              * if we have a filehandle to load from (an empty object created using DTST_RAM)...
  358.              */
  359.             if( ((mvid -> mvid_LoadAll) == FALSE) && (mvid -> input) )
  360.             {
  361.               ObtainSemaphore( (&(mvid -> mvid_SigSem)) );
  362.  
  363.               /* No BitMap loaded ? */
  364.               if( (fn -> fn_BitMap) == NULL )
  365.               {
  366.                 struct FrameNode *ni_frame = FindNextIFrame( i_frame );
  367.  
  368.                 totNumFrames          = i_frame -> fn_Frame - 1UL;                            /* set start of load sequence */
  369.                 mvid -> mvid_MaxFrame = (ni_frame)?(ni_frame -> fn_Frame):(totNumFrames + 1); /* set stop  of load sequence */
  370.  
  371.                 debug_printf( mvid, "ADTM_LOADFRAME: frame %lu %lx %lx I sequence %lu [%lx] - %lu [%lx]\n",
  372.                                 (alf -> alf_TimeStamp), i_frame, fn, totNumFrames, (i_frame -> fn_BMOffset), (mvid -> mvid_MaxFrame),
  373.                                 ((ni_frame)?(ni_frame -> fn_BMOffset):(~0UL)) );
  374.  
  375.                 /* Set "point of return" on decoder exit/error */
  376.                 if( setjmp( exit_buf ) == 0 )
  377.                 {
  378.                   ULONG      data;
  379.                   VidStream *vid_stream = (mvid -> mvid_VidStream);
  380.  
  381.                   mvid -> mvid_retval  = RETURN_OK;
  382.                   mvid -> mvid_retval2 = 0L;
  383.  
  384.                   mvid -> mvid_IndexScan = FALSE;
  385.  
  386.                   /* Initialize bitstream i/o fields. */
  387.                   curBits   = 0UL;
  388.                   bitOffset = 0L;
  389.                   bufLength = 0L;
  390.                   bitBuffer = NULL;
  391.  
  392.                   EOF_flag = FALSE;
  393.  
  394.                   ResetVidStream( mvid, (mvid -> mvid_VidStream) );
  395.  
  396.                   /* Move to the beginning of the I frame start. Use next_start_code to find the
  397.                    * correct start of the start_code; therefore we move a little bit BEFORE the
  398.                    * start that next_start_code can do it's job properly
  399.                    */
  400.                   (void)Seek( (mvid -> input), (i_frame -> fn_BMOffset), OFFSET_BEGINNING );
  401.  
  402.                   {
  403.                     /* Set global curVidStream to vid_stream. Necessary because bit i/o use
  404.                      * curVidStream and are not passed vid_stream. Also set global bitstream
  405.                      * parameters.
  406.                      */
  407.                     curVidStream  =  vid_stream;
  408.                     bitOffset     =  curVidStream -> bit_offset;
  409.                     curBits       = *curVidStream -> buffer << bitOffset;
  410.                     bufLength     =  curVidStream -> buf_length;
  411.                     bitBuffer     =  (ULONG *)curVidStream -> buffer;
  412.                   }
  413.  
  414.                   correct_underflow( mvid ); /* fill buffer */
  415.  
  416.                   do
  417.                   {
  418.                     {
  419.                       /* Copy global bit i/o variables back into vid_stream. */
  420.                       vid_stream -> buffer      = (unsigned int *)bitBuffer;
  421.                       vid_stream -> buf_length  = bufLength;
  422.                       vid_stream -> bit_offset  = bitOffset;
  423.                     }
  424.  
  425.                     mpegVidRsrc( mvid, 0, (mvid -> mvid_VidStream) );
  426.  
  427.                     {
  428.                       /* Set global curVidStream to vid_stream. Necessary because bit i/o use
  429.                        * curVidStream and are not passed vid_stream. Also set global bitstream
  430.                        * parameters.
  431.                        */
  432.                       curVidStream  =  vid_stream;
  433.                       bitOffset     =  curVidStream -> bit_offset;
  434.                       curBits       = *curVidStream -> buffer << bitOffset;
  435.                       bufLength     =  curVidStream -> buf_length;
  436.                       bitBuffer     =  (ULONG *)curVidStream -> buffer;
  437.                     }
  438.  
  439.                     show_bits32( data );
  440.                     debug_printf( mvid, "^^^ next code is %lx\n", data );
  441.                   } while( totNumFrames <= (mvid -> mvid_MaxFrame) );
  442.                 }
  443.  
  444.                 /* Check for errors during loading (if there was not IGNOREERRORS switch set) */
  445.                 if( ((mvid -> mvid_retval) >= RETURN_WARN) && ((mvid -> mvid_IgnoreErrors) == FALSE) )
  446.                 {
  447.                   error = mvid -> mvid_retval2;
  448.                 }
  449.               }
  450.  
  451.               ReleaseSemaphore( (&(mvid -> mvid_SigSem)) );
  452.             }
  453.  
  454.             /* Store frame/context information */
  455.             alf -> alf_Frame    = fn -> fn_Frame;
  456.             alf -> alf_Duration = fn -> fn_Duration;
  457.             alf -> alf_UserData = (APTR)fn;
  458.  
  459.             /* Store bitmap information */
  460.             alf -> alf_BitMap = fn -> fn_BitMap;
  461.             alf -> alf_CMap   = fn -> fn_CMap;
  462.  
  463.             /* Is there a sample to play ? */
  464.             if( fn -> fn_Sample )
  465.             {
  466.               /* Store sound information */
  467.               alf -> alf_Sample       = fn -> fn_Sample;
  468.               alf -> alf_SampleLength = fn -> fn_SampleLength;
  469.               alf -> alf_Period       = fn -> fn_Period;
  470.             }
  471.             else
  472.             {
  473.               /* No sound */
  474.               alf -> alf_Sample       = NULL;
  475.               alf -> alf_SampleLength = 0UL;
  476.               alf -> alf_Period       = 0UL;
  477.             }
  478.  
  479.             /* Frame sequence "in use", even for a unsuccessful result; on error
  480.              * animation.datatype send an ADTM_UNLOADFRAME which frees
  481.              * allocated resources and decreases the "UseCount"...
  482.              */
  483.             i_frame -> fn_UseCount++;
  484.  
  485.             retval = ((error)?(0UL):(ULONG)(alf -> alf_BitMap)); /* Result  */
  486.             SetIoErr( error );                                   /* Result2 */
  487.  
  488.             /* Workaround for a BUG in NOLOADALL mode when the encoder "forgets" to fill a frame.
  489.              * This statement avoids that playback will be stopped in such a case...
  490.              */
  491.             if( (retval == 0UL) && ((mvid -> mvid_LoadAll) == FALSE) && (error == 0L) )
  492.             {
  493.               retval = 1UL;
  494.             }
  495.           }
  496.           else
  497.           {
  498.             SetIoErr( ERROR_OBJECT_NOT_FOUND );
  499.           }
  500.       }
  501.           break;
  502.  
  503. /****** mpegvideo.datatype/ADTM_UNLOADFRAME **********************************
  504. *
  505. *    NAME
  506. *        ADTM_UNLOADFRAME -- Unload frame contents
  507. *
  508. *    FUNCTION
  509. *        The ADTM_UNLOADFRAME method is used to release the contents of a
  510. *        animation frame.
  511. *
  512. *        This method frees the bitmap data found in adtFrame.
  513. *
  514. *    RESULT
  515. *        Returns always 0UL.
  516. *
  517. ******************************************************************************
  518. *
  519. */
  520.       case ADTM_UNLOADFRAME:
  521.       {
  522.           struct FrameNode *fn;
  523.           struct adtFrame  *alf;
  524.  
  525.           mvid = (struct MPEGVideoInstData *)INST_DATA( cl, o );
  526.           alf = (struct adtFrame *)msg;
  527.  
  528.           /* Free bitmaps only if we don't cache the whole anim */
  529.           if( (mvid -> mvid_LoadAll) == FALSE )
  530.           {
  531.             ObtainSemaphore( (&(mvid -> mvid_SigSem)) );
  532.  
  533.             if( fn = (struct FrameNode *)(alf -> alf_UserData) )
  534.             {
  535.               struct FrameNode *i_frame = ((fn -> fn_IFrame)?(fn -> fn_IFrame):(fn));
  536.  
  537.               if( (i_frame -> fn_UseCount) > 0 )
  538.               {
  539.                 i_frame -> fn_UseCount--;
  540.  
  541.                 /* Free an existing bitmap if it isn't in use and if it is NOT the first bitmap */
  542.                 if( ((i_frame -> fn_UseCount) == 0) &&
  543.                     (fn -> fn_BitMap) && ((i_frame -> fn_IsKeyFrame) == FALSE) )
  544.                 {
  545.                   struct FrameNode *worknode = i_frame,
  546.                                    *nextnode;
  547.  
  548.                   /* Free the whole IBBP...I sequence... */
  549.                   while( nextnode = (struct FrameNode *)(worknode -> fn_Node . mln_Succ) )
  550.                   {
  551.                     /* We stop if we reach the next I frame */
  552.                     if( (((worknode -> fn_IFrame) == NULL) && (worknode != i_frame)) )
  553.                     {
  554.                       break;
  555.                     }
  556.  
  557.                     FreeFrameBitMap( mvid, (worknode -> fn_BitMap) );
  558.                     worknode -> fn_BitMap = NULL;
  559.  
  560.                     worknode = nextnode;
  561.                   }
  562.                 }
  563.               }
  564.             }
  565.  
  566.             ReleaseSemaphore( (&(mvid -> mvid_SigSem)) );
  567.           }
  568.  
  569.           /* The frame has been freed ! */
  570.           alf -> alf_UserData = NULL;
  571.       }
  572.           break;
  573.  
  574.       /* Let the superclass handle everything else */
  575.       default:
  576.       {
  577.           retval = DoSuperMethodA( cl, o, msg );
  578.       }
  579.           break;
  580.     }
  581.  
  582.     return( retval );
  583. }
  584.  
  585.  
  586. static
  587. LONG LoadFrames( struct ClassBase *classbase, Object *o )
  588. {
  589.     struct MPEGVideoInstData *mvid  = (struct MPEGVideoInstData *)INST_DATA( (classbase -> cb_Lib . cl_Class), o );
  590.     LONG                      error = 0L;
  591.  
  592.     mvid -> mvid_ClassBase = classbase;
  593.     InitSemaphore( (&(mvid -> mvid_SigSem)) );
  594.     NewList( (struct List *)(&(mvid -> mvid_FrameList)) );
  595.  
  596.     /* Create a memory pool for frame nodes */
  597.     if( mvid -> mvid_Pool = CreatePool( (MEMF_CLEAR | MEMF_PUBLIC), 1024UL, 1024UL ) )
  598.     {
  599.       /* init state... */
  600.       mvid -> mvid_mpegVidRsrc_first = TRUE;
  601.       mvid -> mvid_IndexScan         = TRUE;
  602.  
  603.       /* defaults */
  604.       mvid -> mvid_LoadAll       = TRUE;
  605.       mvid -> mvid_BufLength     = 16384UL;
  606.       mvid -> mvid_Volume        = 63UL;
  607.       mvid -> mvid_gammaCorrect  = 1.0;
  608.       mvid -> mvid_chromaCorrect = 1.0;
  609.       mvid -> mvid_ModeID        = (ULONG)INVALID_ID; /* Means: Choose display mode id automatically */
  610.  
  611.       /* Get file handle, project name and BitMapHeader */
  612.       if( GetDTAttrs( o, DTA_Handle,        (&(mvid -> input)),
  613.                          DTA_Name,          (&(mvid -> mvid_ProjectName)),
  614.                          TAG_DONE ) == 2UL )
  615.       {
  616.         if( mvid -> input )
  617.         {
  618.           /* Read preferences... */
  619.           ReadENVPrefs( classbase, mvid );
  620.  
  621.           /* Set some defaults */
  622.           if( ditherType == 0 )
  623.           {
  624.             ditherType = HAM_DITHER;
  625.           }
  626.  
  627.           /* HAM/FULL_COLOR extra handling stuff... */
  628.           switch( ditherType )
  629.           {
  630.             case HAM_DITHER:
  631.             {
  632.                 mvid -> mvid_ModeID = HAM;
  633.  
  634.                 /* We only support HAM with 6 or 8 planes... */
  635.                 if( (anim_depth != 6UL) && (anim_depth != 8UL) && (anim_depth != 0UL) )
  636.                 {
  637.                   error_printf( mvid, "We only support HAM with 6 or 8 planes, depth %lu not supported\n", anim_depth );
  638.  
  639.                   anim_depth = 0UL; /* use default depth */
  640.                 }
  641.             }
  642.                 break;
  643.  
  644.             case FULL_COLOR_DITHER:
  645.             {
  646.                 if( (anim_depth != 24UL) )
  647.                 {
  648.                   if( (anim_depth != 0UL) && (anim_depth != 32UL) )
  649.                   {
  650.                     error_printf( mvid, "24bit RGB output must have a depth of 24 bit %lu\n", anim_depth );
  651.                   }
  652.  
  653.                   anim_depth = ((mvid -> mvid_UseChunkyMap)?(32UL):(24UL));
  654.                 }
  655.             }
  656.                 break;
  657.  
  658.             case FULL_COLOR_DITHER16:
  659.             {
  660.                 if( anim_depth != 16UL )
  661.                 {
  662.                   if( anim_depth != 0UL )
  663.                   {
  664.                     error_printf( mvid, "16bit RGB output must have a depth of 16 bit\n" );
  665.                   }
  666.  
  667.                   anim_depth = 16UL;
  668.                 }
  669.             }
  670.                 break;
  671.           }
  672.  
  673.           /* Use default depth... */
  674.           if( anim_depth == 0UL )
  675.           {
  676.             switch( ditherType )
  677.             {
  678.               case HAM_DITHER:
  679.               {
  680.                   if( (GfxBase -> ChipRevBits0) & GFXF_AA_LISA )
  681.                   {
  682.                     anim_depth = 8UL;
  683.                   }
  684.                   else
  685.                   {
  686.                     anim_depth = 6UL;
  687.                   }
  688.               }
  689.                   break;
  690.  
  691. #if 0
  692.               case FAST_COLOR_DITHER:
  693. #endif
  694.               case ORDERED_DITHER:
  695.                   anim_depth = 8UL;
  696.                   break;
  697.  
  698.               default:
  699.                   anim_depth = 5UL;
  700.                   break;
  701.             }
  702.           }
  703.  
  704.           /* Use default #?_RANGE values */
  705.           if( (LUM_RANGE == 0UL) || (CR_RANGE == 0UL) || (CB_RANGE == 0UL) )
  706.           {
  707.             if( LUM_RANGE || CR_RANGE || CB_RANGE )
  708.             {
  709.               error_printf( mvid, "(LUM|CR|CB)_RANGE settings ignores. You must set all three at once !\n" );
  710.             }
  711.  
  712.             switch( anim_depth )
  713.             {
  714.               case 8: LUM_RANGE =  7; CR_RANGE = 6; CB_RANGE = 6; break;
  715.               case 7: LUM_RANGE =  5; CR_RANGE = 5; CB_RANGE = 5; break;
  716.               case 6: LUM_RANGE =  4; CR_RANGE = 4; CB_RANGE = 4; break;
  717.               case 5: LUM_RANGE =  3; CR_RANGE = 3; CB_RANGE = 3; break;
  718.               case 4: LUM_RANGE = 16; CR_RANGE = 1; CB_RANGE = 1; break;
  719.               case 3: LUM_RANGE =  8; CR_RANGE = 1; CB_RANGE = 1; break;
  720.               case 2: LUM_RANGE =  4; CR_RANGE = 1; CB_RANGE = 1; break;
  721.               case 1: LUM_RANGE =  2; CR_RANGE = 1; CB_RANGE = 1; break;
  722.             }
  723.           }
  724.  
  725.           /* round width */
  726.           if( anim_width )
  727.           {
  728.             /* width must be divisible by 16... */
  729.             anim_width = (anim_width + 15UL) & ~15UL;
  730.           }
  731.  
  732.           /* round height */
  733.           if( anim_height )
  734.           {
  735.             /* height must be divisible by 16... */
  736.             anim_height = (anim_height + 15) & ~15;
  737.           }
  738.  
  739.           /* Pop up progress bar, if requested */
  740.           CreateProgressRequester( mvid );
  741.  
  742.           /* Set "point of return" on decoder exit/error */
  743.           if( setjmp( exit_buf ) == 0 )
  744.           {
  745.             /* The following set up is not needed for direct RGB-coded bitmaps */
  746.             if( anim_depth <= 8UL )
  747.             {
  748.               lum_values = (UBYTE *)mymalloc( mvid, (size_t)(LUM_RANGE * sizeof( UBYTE )) );
  749.               cr_values  = (UBYTE *)mymalloc( mvid, (size_t)(CR_RANGE  * sizeof( UBYTE )) );
  750.               cb_values  = (UBYTE *)mymalloc( mvid, (size_t)(CB_RANGE  * sizeof( UBYTE )) );
  751.               mappixel   =  (LONG *)mymalloc( mvid, (size_t)((MAX( (LUM_RANGE * CR_RANGE * CB_RANGE), 256UL ) + 1UL) * sizeof( LONG )) );
  752.             }
  753.  
  754.             switch( ditherType )
  755.             {
  756.               case FULL_COLOR_DITHER:
  757.               case FULL_COLOR_DITHER16:
  758.               {
  759.                   /* Set up 24/16 bit color settings */
  760.                   InitColorDither( mvid );
  761.               }
  762.                   break;
  763.  
  764.               case HAM_DITHER:
  765.               {
  766.                   /* Set up 24 bit color settings */
  767.                   InitColorDither( mvid );
  768.  
  769.                   InitHAMDisplay( mvid );
  770.               }
  771.                   break;
  772.  
  773.               case ORDERED_DITHER:
  774.               {
  775.                   InitColor( mvid );
  776.                   InitOrderedDither( mvid );
  777.                   InitDisplay( mvid );
  778.               }
  779.                   break;
  780.  
  781.               case GRAY_DITHER:
  782.               {
  783.                   InitGrayDisplay( mvid );
  784.               }
  785.                   break;
  786.  
  787. #if 0
  788.               case FAST_COLOR_DITHER:
  789.               {
  790.                   /* Set up dicecolor requirements (base palette) */
  791.                   InitColor( mvid );
  792.                   InitOrderedDither( mvid );
  793.                   InitDisplay( mvid );
  794.  
  795.                   /* Set up 24 bit color settings */
  796.                   InitColorDither( mvid );
  797.               }
  798.                   break;
  799. #endif
  800.             }
  801.  
  802.             loadvideo( mvid );
  803.           }
  804.  
  805.           /* If we have nothing to load anymore, shut down the decoder here... */
  806.           if( (mvid -> mvid_LoadAll) == TRUE )
  807.           {
  808.             mpeg_closedown( mvid );
  809.           }
  810.  
  811.           /* We're done with the scan */
  812.           DeleteProgressRequester( mvid );
  813.  
  814.           /* Check for errors during loading (if there was not IGNOREERRORS switch set) */
  815.           if( ((mvid -> mvid_retval) <= RETURN_WARN) || (mvid -> mvid_IgnoreErrors) )
  816.           {
  817.             verbose_printf( mvid, "width %lu height %lu depth %lu frames %lu tpf %lu\n", anim_width, anim_height, anim_depth, totNumFrames, xtpf );
  818.  
  819.             /* Anything to work on ? */
  820.             if( anim_width && anim_height && anim_depth && totNumFrames )
  821.             {
  822.               struct ColorRegister *acm;
  823.               ULONG                *acregs;
  824.               ULONG                 nc;
  825.  
  826.               /* Key bitmap ? */
  827.               if( mvid -> mvid_KeyBitMap )
  828.               {
  829.                 ULONG numcolors;
  830.  
  831.                 if( (mvid -> mvid_ModeID) == INVALID_ID )
  832.                 {
  833.                   /* BUG: Does currently not support SUPERHIRES modes */
  834.                   if( anim_width >= 640UL )
  835.                   {
  836.                     if( anim_height >= 400 )
  837.                     {
  838.                       mvid -> mvid_ModeID = HIRESLACE_KEY;
  839.                     }
  840.                     else
  841.                     {
  842.                       mvid -> mvid_ModeID = HIRES_KEY;
  843.                     }
  844.                   }
  845.                   else
  846.                   {
  847.                     if( anim_height >= 400 )
  848.                     {
  849.                       mvid -> mvid_ModeID = LORESLACE_KEY;
  850.                     }
  851.                     else
  852.                     {
  853.                       mvid -> mvid_ModeID = LORES_KEY;
  854.                     }
  855.                   }
  856.                 }
  857.  
  858.                 numcolors = ((mvid -> mvid_PalettePerFrame)?(1UL << anim_depth):(used_cnt));
  859.  
  860.                 /* Store misc attributes */
  861.                 SetDTAttrs( o, NULL, NULL, DTA_ObjName,      (mvid -> mvid_ProjectName),
  862.                                            DTA_NominalHoriz, anim_width,
  863.                                            DTA_NominalVert,  anim_height,
  864.                                            ADTA_ModeID,      (mvid -> mvid_ModeID),
  865.                                            ADTA_Width,       anim_width,
  866.                                            ADTA_Height,      anim_height,
  867.                                            ADTA_Depth,       anim_depth,
  868.                                            ADTA_NumColors,   numcolors,
  869.                                            TAG_DONE );
  870.  
  871.  
  872.                 /* Get color context */
  873.                 if( GetDTAttrs( o,
  874.                                 ADTA_ColorRegisters, (&acm),
  875.                                 ADTA_CRegs,          (&acregs),
  876.                                 ADTA_NumColors,      (&nc),
  877.                                 TAG_DONE ) == 3UL )
  878.                 {
  879.                   /* All valid ? */
  880.                   if( (acm && acregs && nc) || (numcolors == 0UL) )
  881.                   {
  882.                     ULONG i;
  883.  
  884.                     /* Copy colors from used_colors array into obj's acregs and acm */
  885.                     for( i = 0UL ; i < nc ; i++ )
  886.                     {
  887.                       ULONG r,
  888.                             b,
  889.                             g;
  890.  
  891.                       acm[ i ] = used_colors[ i ];
  892.  
  893.                       /* Replicate the color information.
  894.                        * This surrounds an OS bug which uses the low-oreder bytes of the 32-bit colors
  895.                        * instead of the high order ones
  896.                        */
  897.                       r = used_colors[ i ] . red;
  898.                       g = used_colors[ i ] . green;
  899.                       b = used_colors[ i ] . blue;
  900.  
  901.                       acregs[ (i * 3) + 0 ] = r * 0x01010101UL;
  902.                       acregs[ (i * 3) + 1 ] = g * 0x01010101UL;
  903.                       acregs[ (i * 3) + 2 ] = b * 0x01010101UL;
  904.                     }
  905.  
  906.                     /* Set up mvid_FirstFrameNode */
  907.                     mvid -> mvid_FirstFrameNode = (struct FrameNode *)(mvid -> mvid_FrameList . mlh_Head);
  908.  
  909.                     /* Copy first frame into key bitmap */
  910.                     CopyBitMap( classbase, (mvid -> mvid_KeyBitMap), (mvid -> mvid_FirstFrameNode -> fn_BitMap), (ULONG)anim_width, (ULONG)anim_height );
  911.  
  912.                     if( (mvid -> mvid_TicksPerFrame) == 0UL )
  913.                     {
  914.                       mvid -> mvid_TicksPerFrame = xtpf;
  915.                     }
  916.  
  917.                     AttachSample( mvid );
  918.  
  919.                     /* Set up required attributes */
  920.                     SetDTAttrs( o, NULL, NULL, ADTA_Frames,                            totNumFrames,
  921.                                                XTAG( ISV41,    ADTA_TicksPerFrame   ), (mvid -> mvid_TicksPerFrame),
  922.                                                XTAG( (!ISV41), ADTA_FramesPerSecond ), (TICK_FREQ / (mvid -> mvid_TicksPerFrame)),
  923.                                                ADTA_KeyFrame,                          (mvid -> mvid_KeyBitMap),
  924.                                                ADTA_Sample,                            (mvid -> mvid_FirstFrameNode -> fn_Sample),
  925.                                                ADTA_SampleLength,                      (mvid -> mvid_FirstFrameNode -> fn_SampleLength),
  926.                                                ADTA_Period,                            (mvid -> mvid_FirstFrameNode -> fn_Period),
  927.                                                ADTA_Volume,                            (mvid -> mvid_Volume),
  928.                                                ADTA_Cycles,                            1UL,
  929.                                                TAG_DONE );
  930.                   }
  931.                   else
  932.                   {
  933.                     /* no color table etc. from superclass */
  934.                     error = ERROR_NO_FREE_STORE;
  935.                   }
  936.                 }
  937.                 else
  938.                 {
  939.                   /* can't get required args from superclass */
  940.                   error = ERROR_NO_FREE_STORE;
  941.                 }
  942.               }
  943.               else
  944.               {
  945.                 /* can't alloc key bitmap */
  946.                 error = ERROR_NO_FREE_STORE;
  947.               }
  948.             }
  949.             else
  950.             {
  951.               /* something during load went wrong, we got no frames */
  952.               error = DTERROR_NOT_ENOUGH_DATA;
  953.             }
  954.           }
  955.           else
  956.           {
  957.             /* error during loading */
  958.             error = mvid -> mvid_retval2;
  959.           }
  960.         }
  961.         else
  962.         {
  963.           /* no fh */
  964.           error = ERROR_REQUIRED_ARG_MISSING;
  965.         }
  966.       }
  967.       else
  968.       {
  969.         /* can't get required attributes from superclass */
  970.         error = ERROR_REQUIRED_ARG_MISSING;
  971.       }
  972.     }
  973.     else
  974.     {
  975.       /* no memory pool */
  976.       error = ERROR_NO_FREE_STORE;
  977.     }
  978.     
  979.     return( error );
  980. }
  981.  
  982.  
  983. struct FrameNode *AllocFrameNode( struct ClassBase *classbase, APTR pool )
  984. {
  985.     return( (struct FrameNode *)AllocPooled( pool, (ULONG)sizeof( struct FrameNode ) ) );
  986. }
  987.  
  988.  
  989. void FreeFrameNode( struct MPEGVideoInstData *mvid, struct FrameNode *fn )
  990. {
  991.     struct ClassBase *classbase = mvid -> mvid_ClassBase;
  992.  
  993.     if( fn )
  994.     {
  995.       FreeFrameBitMap( mvid, (fn -> fn_BitMap) );
  996.  
  997.       FreeColorMap( (fn -> fn_CMap) );
  998.  
  999.       FreePooled( (mvid -> mvid_Pool), (APTR)fn, (ULONG)sizeof( struct FrameNode ) );
  1000.     }
  1001. }
  1002.  
  1003.  
  1004. struct FrameNode *FindFrameNode( struct MinList *fnl, ULONG timestamp )
  1005. {
  1006.     if( fnl )
  1007.     {
  1008.       struct FrameNode *worknode,
  1009.                        *nextnode,
  1010.                        *prevnode;
  1011.  
  1012.       prevnode = worknode = (struct FrameNode *)(fnl -> mlh_Head);
  1013.  
  1014.       while( nextnode = (struct FrameNode *)(worknode -> fn_Node . mln_Succ) )
  1015.       {
  1016.         if( (worknode -> fn_TimeStamp) > timestamp )
  1017.         {
  1018.           return( prevnode );
  1019.         }
  1020.  
  1021.         prevnode = worknode;
  1022.         worknode = nextnode;
  1023.       }
  1024.  
  1025.       if( !IsListEmpty( ((struct List *)fnl) ) )
  1026.       {
  1027.         return( prevnode );
  1028.       }
  1029.     }
  1030.  
  1031.     return( NULL );
  1032. }
  1033.  
  1034.  
  1035. static
  1036. struct FrameNode *FindNextIFrame( struct FrameNode *fn )
  1037. {
  1038.     if( fn )
  1039.     {
  1040.       struct FrameNode *worknode,
  1041.                        *nextnode;
  1042.  
  1043.       if( worknode = (struct FrameNode *)(fn -> fn_Node . mln_Succ) )
  1044.       {
  1045.         while( nextnode = (struct FrameNode *)(worknode -> fn_Node . mln_Succ) )
  1046.         {
  1047.           if( (worknode -> fn_IFrame) == NULL )
  1048.           {
  1049.             return( worknode );
  1050.           }
  1051.  
  1052.           worknode = nextnode;
  1053.         }
  1054.       }
  1055.     }
  1056.  
  1057.     return( NULL );
  1058. }
  1059.  
  1060.  
  1061. void mysprintf( struct ClassBase *classbase, STRPTR buffer, STRPTR fmt, ... )
  1062. {
  1063.     APTR args;
  1064.  
  1065.     args = (APTR)((&fmt) + 1);
  1066.  
  1067.     RawDoFmt( fmt, args, (void (*))"\x16\xc0\x4e\x75", buffer );
  1068. }
  1069.  
  1070.  
  1071. void verbose_printf( struct MPEGVideoInstData *mvid, STRPTR format, ... )
  1072. {
  1073.     if( mvid -> mvid_VerboseOutput )
  1074.     {
  1075.       struct ClassBase *classbase = mvid -> mvid_ClassBase;
  1076.  
  1077.       VFPrintf( (mvid -> mvid_VerboseOutput), format, (APTR)((&format) + 1) );
  1078.     }
  1079. }
  1080.  
  1081.  
  1082. void debug_printf( struct MPEGVideoInstData *mvid, STRPTR format, ... )
  1083. {
  1084.     if( (mvid -> mvid_VerboseOutput) && (mvid -> mvid_DoDebug) )
  1085.     {
  1086.       struct ClassBase *classbase = mvid -> mvid_ClassBase;
  1087.  
  1088.       VFPrintf( (mvid -> mvid_VerboseOutput), format, (APTR)((&format) + 1) );
  1089.     }
  1090. }
  1091.  
  1092.  
  1093. void syntax_printf( struct MPEGVideoInstData *mvid, STRPTR format, ... )
  1094. {
  1095.     if( (mvid -> mvid_VerboseOutput) && (mvid -> mvid_DoSyntax) )
  1096.     {
  1097.       struct ClassBase *classbase = mvid -> mvid_ClassBase;
  1098.  
  1099.       VFPrintf( (mvid -> mvid_VerboseOutput), format, (APTR)((&format) + 1) );
  1100.     }
  1101. }
  1102.  
  1103.  
  1104. void error_printf( struct MPEGVideoInstData *mvid, STRPTR format, ... )
  1105. {
  1106.     struct ClassBase *classbase = mvid -> mvid_ClassBase;
  1107.  
  1108.     OpenLogfile( classbase, mvid );
  1109.  
  1110.     if( mvid -> mvid_VerboseOutput )
  1111.     {
  1112.       VFPrintf( (mvid -> mvid_VerboseOutput), format, (APTR)((&format) + 1) );
  1113.     }
  1114. }
  1115.  
  1116.  
  1117. static
  1118. void CopyBitMap( struct ClassBase *classbase, struct BitMap *dest, struct BitMap *src, ULONG width, ULONG height )
  1119. {
  1120.     if( dest && src )
  1121.     {
  1122.       if( CyberGfxBase )
  1123.       {
  1124.         /* Assumption: If a non-planar bitmap occurs BltBitMap should be able
  1125.          * to blit it into a planar one
  1126.          */
  1127.         BltBitMap( src, 0L, 0L, dest, 0L, 0L, width, height, 0xC0UL, 0xFFUL, NULL );
  1128.  
  1129.         WaitBlit();
  1130.       }
  1131.       else
  1132.       {
  1133.         ULONG planesize = (ULONG)(dest -> BytesPerRow) * (ULONG)(dest -> Rows);
  1134.         UWORD i;
  1135.  
  1136.         for( i = 0U ; i < (dest -> Depth) ; i++ )
  1137.         {
  1138.           CopyMem( (src -> Planes[ i ]), (dest -> Planes[ i ]), planesize );
  1139.         }
  1140.       }
  1141.     }
  1142. }
  1143.  
  1144.  
  1145. static
  1146. struct BitMap *AllocFastBitMap( struct MPEGVideoInstData *mvid, ULONG width, ULONG height, ULONG depth )
  1147. {
  1148.     struct ClassBase *classbase = mvid -> mvid_ClassBase;
  1149.     struct BitMap    *bm;
  1150.     ULONG             planesize,
  1151.                       moredepthsize,
  1152.                       size;
  1153.  
  1154.     planesize      = (ULONG)RASSIZE( width, height ) + 64UL;
  1155.     moredepthsize  = (depth > 8UL)?((depth - 8UL) * sizeof( PLANEPTR )):(0UL);
  1156.     size           = ((ULONG)sizeof( struct BitMap )) + moredepthsize + (planesize * depth);
  1157.  
  1158.     if( mvid -> mvid_UseVMM )
  1159.     {
  1160.       bm = (struct BitMap *)AllocVVec( size, 0UL );
  1161.     }
  1162.     else
  1163.     {
  1164.       bm = (struct BitMap *)AllocVec( size, MEMF_PUBLIC );
  1165.     }
  1166.  
  1167.     if( bm )
  1168.     {
  1169.       PLANEPTR plane;
  1170.       UWORD    pl;
  1171.  
  1172.       InitBitMap( bm, depth, width, height );
  1173.  
  1174.       plane = (PLANEPTR)(((UBYTE *)(bm + 1)) + moredepthsize); /* First plane follows struct BitMap */
  1175.  
  1176.       /* Set up plane data */
  1177.       pl = 0U;
  1178.  
  1179.       /* Set up plane ptrs */
  1180.       while( pl < depth )
  1181.       {
  1182.         bm -> Planes[ pl ] = plane;
  1183.  
  1184.         plane = (PLANEPTR)(((UBYTE *)plane) + planesize);
  1185.         pl++;
  1186.       }
  1187.  
  1188.       /* Clear the remaining plane ptrs (only of standart 8 plane struct bitmap) */
  1189.       while( pl < 8U )
  1190.       {
  1191.         bm -> Planes[ pl ] = NULL;
  1192.  
  1193.         pl++;
  1194.       }
  1195.     }
  1196.  
  1197.     return( bm );
  1198. }
  1199.  
  1200.  
  1201. struct BitMap *AllocFrameBitMap( struct MPEGVideoInstData *mvid )
  1202. {
  1203.     struct ClassBase *classbase = mvid -> mvid_ClassBase;
  1204.  
  1205.     if( mvid -> mvid_UseChunkyMap )
  1206.     {
  1207.       return( AllocBitMap( (ULONG)anim_width, (ULONG)anim_height, (ULONG)anim_depth, (BMF_SPECIALFMT | SHIFT_PIXFMT( pixfmt )), NULL ) );
  1208.     }
  1209.     else
  1210.     {
  1211.       return( AllocFastBitMap( mvid, (ULONG)anim_width, (ULONG)anim_height, (ULONG)anim_depth ) );
  1212.     }
  1213. }
  1214.  
  1215.  
  1216. void FreeFrameBitMap( struct MPEGVideoInstData *mvid, struct BitMap *bm )
  1217. {
  1218.     if( bm )
  1219.     {
  1220.       struct ClassBase *classbase = mvid -> mvid_ClassBase;
  1221.  
  1222.       if( mvid -> mvid_UseChunkyMap )
  1223.       {
  1224.         FreeBitMap( bm );
  1225.       }
  1226.       else
  1227.       {
  1228.         if( mvid -> mvid_UseVMM )
  1229.         {
  1230.           FreeVVec( (APTR)bm );
  1231.         }
  1232.         else
  1233.         {
  1234.           FreeVec( (APTR)bm );
  1235.         }
  1236.       }
  1237.     }
  1238. }
  1239.  
  1240.  
  1241. /****** mpegvideo.datatype/preferences ***************************************
  1242. *
  1243. *   NAME
  1244. *       preferences
  1245. *
  1246. *   DESCRIPTION
  1247. *       The "ENV:Classes/DataTypes/mpegvideo.prefs" file contains global
  1248. *       settings for the datatype.
  1249. *       The preferences file is an ASCII file containing one line where the
  1250. *       preferences can be set.
  1251. *       It can be superset by a local variable with the same name.
  1252. *
  1253. *       Each line can contain settings, special settings for some projects
  1254. *       can be set using the MATCHPROJECT option.
  1255. *       Lines beginning with a '#' or ';' chars are treated as comments.
  1256. *       Lines are limitted to 256 chars.
  1257. *
  1258. *   TEMPLATE
  1259. *       MATCHPROJECT/K,MODEID/K/N,WIDTH/K/N,HEIGHT/K/N,DEPTH/K/N,DITHER/K,
  1260. *       LUM_RANGE/K/N,CR_RANGE/K/N,CB_RANGE/K/N,COLORERROR/K/N,
  1261. *       PALETTEPERFRAME/S,NOPALETTEPERFRAME/S,GAMMACORRECT/K,CHROMACORRECT/K,
  1262. *       MAXFRAME/K/N,SKIPFRAMES/K/N,FPS/K/N,PFRAMES/S,NOPFRAMES/S,BFRAMES/S,
  1263. *       NOBFRAMES/S,SAMPLE/K,VOLUME/K/N,BUFFER/K/N,LOADALL/S,NOLOADALL/S,
  1264. *       USEVMM/S,MINTOTALMEM/K/N,IGNOREERRORS/S,VERBOSE/S,PROGRESSGAUGE/S,
  1265. *       NOPROGRESSGAUGE/S,QUALITY/S,NOQUALITY/S
  1266. *
  1267. *       MATCHPROJECT -- The settings in this line belongs only to this
  1268. *           project(s), e.g. if the case-insensitive pattern does not match,
  1269. *           this line is ignored.
  1270. *           The maximum length of the pattern is 128 chars.
  1271. *           Defaults to #?, which matches any project.
  1272. *
  1273. *       MODEID -- Select screen mode id of datatype (will be stored in
  1274. *           ADTA_ModeID). Note that the DOS ReadArgs function used for parsing
  1275. *           fetches a SIGNED long. The bit 31 will be represented by minus
  1276. *           '-'. (example: "MODEID=266240" sets the mode to the A2024 screen
  1277. *           mode id)
  1278. *           Defaults to -1, which means: Use the best screenmode available
  1279. *           for the given width, height and depth.
  1280. *
  1281. *       WIDTH -- Set the animation's width. The video will be scaled to this
  1282. *           width.
  1283. *           Defaults to 0, which means: Use video's width.
  1284. *
  1285. *       HEIGHT -- Set the animation's height. The video will be scaled to this
  1286. *           height.
  1287. *           Defaults to 0, which means: Use video's height.
  1288. *
  1289. *       DEPTH -- depth for the selected scaling mode
  1290. *           A value describing the "depth" of the animation.
  1291. *           1 upto 8 are valid, under- or overflows will be truncated
  1292. *           to the maximum supported.
  1293. *           The default depth will be selected by the DITHER mode.
  1294. *
  1295. *       DITHER -- dither type, one of
  1296. *           GRAY            -- grayscale output
  1297. *           HAM             -- ham ham6/ham8 etc. (default)
  1298. *           EHB             -- extra halfbright                     (n/a)
  1299. *           COLOR           -- color output
  1300. *           ORDERED         -- ordered dither
  1301. *           24BITCHUNKY     -- true color, 24 bit
  1302. *           16BITCHUNKY     -- true color, 16 bit
  1303. *           24BITPLANAR     -- true color, 24 bit
  1304. *
  1305. *           GRAY is the grayscale mode.
  1306. *               If no depth is given, the depth default to 5 (32 colors).
  1307. *
  1308. *           HAM (hold-and-modify) mode: Either HAM6 or HAM8, set by the depth
  1309. *               option. If no depth is given, this defaults to 6 for OCS/ECS
  1310. *               and 8 for AGA/AAA machines.
  1311. *               This is the default dither mode if no DITHER option is given.
  1312. *
  1313. *           EHB (extra halfbright mode):
  1314. *               If no depth is given, the depth default to 6 (32/64 colors).
  1315. *               not implemented yet
  1316. *
  1317. *           COLOR remaps the frames into a fixed color space.
  1318. *               If no depth is given, the depth default to 8 (256 colors).
  1319. *
  1320. *           ORDERED uses ordered dithering.
  1321. *               If no depth is given, the depth default to 8 (256 colors).
  1322. *
  1323. *           24BITCHUNKY uses chunkypixel CyberGFX bitmaps
  1324. *               Fixed to a depth of 32 (XRGB).
  1325. *               Requires at least animation.datatype V41.3.
  1326. *
  1327. *           16BITCHUNKY uses chunkypixel CyberGFX bitmaps
  1328. *               Fixed to a depth of 16 (XRGB).
  1329. *               Requires at least animation.datatype V41.3.
  1330. *
  1331. *           24BITPLANAR uses a planar 24 bit depth bitmap (non-interleaved)
  1332. *               Fixed to a depth of 24 (RGB).
  1333. *               Requires at least animation.datatype V41.3.
  1334. *
  1335. *           Defaults to HAM.
  1336. *
  1337. *       LUM_RANGE -- sets the number of colors assigned to the luminance
  1338. *           component when dithering the image.  The product of LUM_RANGE,
  1339. *           CR_RANGE and CB_RANGE should be less than the number of colors
  1340. *           selected by the DEPTH option.
  1341. *           This will only affect ORDERED and COLOR dithering and the base
  1342. *           palette of the DICECOLOR remapping.
  1343. *           Any value between 1 upto 255 is allowed, 0 is treated as 1.
  1344. *
  1345. *           Defaults: see DEFAULTS section below
  1346. *
  1347. *       CR_RANGE -- sets the number of colors assigned to the red component of
  1348. *           the chrominace range when dithering the image.  The product of
  1349. *           LUM_RANGE, CR_RANGE and CB_RANGE should be less than the number of
  1350. *           colors selected by the DEPTH option.
  1351. *           This will only affect ORDERED and COLOR dithering and the base
  1352. *           palette of the DICECOLOR remapping.
  1353. *           Any value between 1 upto 255 is allowed, 0 is treated as 1.
  1354. *
  1355. *           Defaults: see DEFAULTS section below
  1356. *
  1357. *       CB_RANGE -- sets the number of colors assigned to the blue component
  1358. *           of the chrominace range when dithering the image.  The product of
  1359. *           LUM_RANGE, CR_RANGE and CB_RANGE should be less than the number of
  1360. *           colors selected by the DEPTH option.
  1361. *           This will only affect ORDERED and COLOR dithering and the base
  1362. *           palette of the DICECOLOR remapping.
  1363. *           Any value between 1 upto 255 is allowed, 0 is treated as 1.
  1364. *
  1365. *           Defaults: see DEFAULTS section below
  1366. *
  1367. *       COLORERROR -- Set the error range when allocating colors.
  1368. *           The error range is used for color matching
  1369. *           (like this: if( ABS( (pixel . red) - (colormap . red) ) +
  1370. *                       ABS( <dito. green> ) + ABS( <dito. blue> )
  1371. *                       < colorerror ) then use this color index).
  1372. *           A low value (0) means high quality remapping and slow remapping,
  1373. *           high values (50) means low quality (using less color indexes).
  1374. *           The value set here will also affect DICECOLOR remapping, because
  1375. *           the search algorithm is the same.
  1376. *
  1377. *           Defaults to 0.
  1378. *
  1379. *       PALETTEPERFRAME -- Create a own palette for each frame.
  1380. *           __Currently__ a NOP for HAM dithering and always a NOP
  1381. *           for all direct-RGB output modes (24BITCHUNKY, 16BITCHUNKY, 
  1382. *           24BITPLANAR).
  1383. *
  1384. *           Note that this option requires animation.datatype V41 to work.
  1385. *
  1386. *       NOPALETTERPERFRAME -- Turns PALETTEPERFRAME switch off.
  1387. *
  1388. *       GAMMACORRECT -- Gamma correction value (defined as fixed point
  1389. *           number).
  1390. *           Defaults to "1.0".
  1391. *
  1392. *       CHROMACORRECT -- Chroma correction value (defined as fixed point
  1393. *           number).
  1394. *           Defaults to "1.0".
  1395. *
  1396. *       MAXFRAME -- Maximum number of frames to load.
  1397. *           Defaults to 0, which means: Load all frames.
  1398. *
  1399. *       SKIPFRAMES -- Load only the n-th frame of an animation.
  1400. *           The internal timing (e.g. time code) is not affected, so
  1401. *           the FPS value will be correct.
  1402. *           Defaults to 0 which means: Skip no frame.
  1403. *
  1404. *           Note that this option requires animation.datatype V41 to work
  1405. *           properly.
  1406. *
  1407. *       FPS -- frames per second
  1408. *           Defaults to 0, which means: overtake fps rate from video stream.
  1409. *           Setting the FPS value also affects an attched sound. The period
  1410. *           of the sample (e.g. the playback speed) will everytimes as long
  1411. *           as the frame is displayed.
  1412. *
  1413. *       PFRAMES -- Turns off the NOPFRAMES option.
  1414. *           Default is on.
  1415. *
  1416. *       NOPFRAMES -- ignore any type P frames (predicted frames) when loading.
  1417. *
  1418. *       BFRAMES -- Turns off the NOBFRAMES option.
  1419. *           Default is on.
  1420. *
  1421. *       NOBFRAMES -- ignore any type B frames (bidirectional frames) when
  1422. *           loading.
  1423. *           Default is off.
  1424. *
  1425. *       SAMPLE -- Attach the given sample to the animation. The sample will
  1426. *           be loaded using datatypes (GID_SOUND).
  1427. *           Only one sample can be attached to one video stream, any following
  1428. *           attempt to attach the sample will be ignored.
  1429. *
  1430. *           Default: no sample
  1431. *
  1432. *       VOLUME -- Volume of the sound when playing.
  1433. *           Defaults to 63, which is the maximum. A value greater than 64 will
  1434. *           be set to 63.
  1435. *
  1436. *       BUFFER -- read buffers size. Minimum is 2048, lower values are set to
  1437. *           2048.
  1438. *           Defaults to 16384.
  1439. *
  1440. *       LOADALL -- load all frames before displaying it.
  1441. *
  1442. *       NOLOADALL -- turns off LOADALL switch.
  1443. *
  1444. *       USEVMM -- Use Martin Apel's vmm.library for bitmaps.
  1445. *           The verbose output will tell you if VMM memory will be used or
  1446. *           not.
  1447. *           This option is useless if CyberGFX bitmaps are used !
  1448. *           Default is off.
  1449. *
  1450. *       NOUSEVMM -- Turn VMM usage for bitmaps off.
  1451. *
  1452. *       MINTOTALMEM -- Minimum total memory available. If less memory
  1453. *           available, abort loading.
  1454. *           Defaults to 0, which means: Don't use this option.
  1455. *
  1456. *       IGNOREERRORS -- Ignore errors while parsing/decoding etc.
  1457. *           Usefull if a syntax error or read error (which may occur with
  1458. *           some old, buggy CD filesystems) happens.
  1459. *           Default is off.
  1460. *
  1461. *       VERBOSE -- Verbose output. Prints out current frame etc., some
  1462. *           statistical information and maybe, debugging infos.
  1463. *           Verbose output will be printed in a console window
  1464. *           ("CON://///auto/wait/close/inactive/MPEG Video DataType").
  1465. *           Default is off.
  1466. *
  1467. *       PROGRESSGAUGE -- Display a load progress gauge.
  1468. *           Default is on.
  1469. *
  1470. *       NOPROGRESSGAUGE -- Disables the progress gauge which is displayed
  1471. *           during loading of the mpeg stream.
  1472. *           Default is off.
  1473. *
  1474. *       QUALITY -- If set, mpegvideo.datatype uses floating-point dct
  1475. *           decoding, which results in a better output quality.
  1476. *           Default is off.
  1477. *
  1478. *       NOQUALITY -- Turns QUALITY switch off.
  1479. *           Default is on.
  1480. *
  1481. *   DEFAULTS
  1482. *       Defaults for the options are noted above.
  1483. *
  1484. *       LUM_RANGE, CR_RANGE, CB_RANGE options have defaults based on the
  1485. *       depth:
  1486. *
  1487. *       depth | LUM_RANGE | CR_RANGE | CB_RANGE | comment
  1488. *       ------+-----------+----------+----------+----------------------
  1489. *          8  |         7 |        6 |       6  | color output
  1490. *          7  |         5 |        5 |       5  | color output
  1491. *          6  |         4 |        4 |       4  | color output
  1492. *          5  |         3 |        3 |       3  | color output
  1493. *          4  |        16 |        1 |       1  | grayscale output
  1494. *          3  |         8 |        1 |       1  | grayscale output
  1495. *          2  |         4 |        1 |       1  | grayscale output
  1496. *          1  |         2 |        1 |       1  | black & white output
  1497. *
  1498. *   NOTE
  1499. *       An invalid prefs file line will force the default settings for this
  1500. *       line and the VERBOSE option.
  1501. *
  1502. *   BUGS
  1503. *       - Low memory may cause that the prefs file won't be parsed.
  1504. *
  1505. *       - Lines are limitted to 256 chars
  1506. *
  1507. ******************************************************************************
  1508. *
  1509. */
  1510.  
  1511.  
  1512. static
  1513. STRPTR GetPrefsVar( struct ClassBase *classbase, STRPTR name )
  1514. {
  1515.           STRPTR buff;
  1516.     const ULONG  buffsize = 16UL;
  1517.  
  1518.     if( buff = (STRPTR)AllocVec( (buffsize + 2UL), (MEMF_PUBLIC | MEMF_CLEAR) ) )
  1519.     {
  1520.       if( GetVar( name, buff, buffsize, GVF_BINARY_VAR ) != (-1L) )
  1521.       {
  1522.         ULONG varsize = IoErr();
  1523.  
  1524.         varsize += 2UL;
  1525.  
  1526.         if( varsize > buffsize )
  1527.         {
  1528.           FreeVec( buff );
  1529.  
  1530.           if( buff = (STRPTR)AllocVec( (varsize + 2UL), (MEMF_PUBLIC | MEMF_CLEAR) ) )
  1531.           {
  1532.             if( GetVar( name, buff, varsize, GVF_BINARY_VAR ) != (-1L) )
  1533.             {
  1534.               return( buff );
  1535.             }
  1536.           }
  1537.         }
  1538.         else
  1539.         {
  1540.           return( buff );
  1541.         }
  1542.       }
  1543.  
  1544.       FreeVec( buff );
  1545.     }
  1546.  
  1547.     return( NULL );
  1548. }
  1549.  
  1550.  
  1551. static
  1552. BOOL matchstr( struct ClassBase *classbase, STRPTR pat, STRPTR s )
  1553. {
  1554.     TEXT buff[ 512 ];
  1555.  
  1556.     if( pat && s )
  1557.     {
  1558.       if( ParsePatternNoCase( pat, buff, (sizeof( buff ) - 1) ) != (-1L) )
  1559.       {
  1560.         if( MatchPatternNoCase( buff, s ) )
  1561.         {
  1562.           return( TRUE );
  1563.         }
  1564.       }
  1565.     }
  1566.  
  1567.     return( FALSE );
  1568. }
  1569.  
  1570.  
  1571. static
  1572. void ReadENVPrefs( struct ClassBase *classbase, struct MPEGVideoInstData *mvid )
  1573. {
  1574.     struct RDArgs envvarrda =
  1575.     {
  1576.       NULL,
  1577.       256L,
  1578.       0L,
  1579.       0L,
  1580.       NULL,
  1581.       0L,
  1582.       NULL,
  1583.       RDAF_NOPROMPT
  1584.     };
  1585.  
  1586.     struct
  1587.     {
  1588.       STRPTR  matchproject;
  1589.       long   *modeid;
  1590.       long   *width;
  1591.       long   *height;
  1592.       long   *depth;
  1593.       STRPTR  dither;
  1594.       long   *lum_range;
  1595.       long   *cr_range;
  1596.       long   *cb_range;
  1597.       long   *colorerror;
  1598.       long   *paletteperframe;
  1599.       long   *nopaletteperframe;
  1600.       STRPTR  gammacorrect;
  1601.       STRPTR  chromacorrect;
  1602.       long   *maxframe;
  1603.       long   *skipframes;
  1604.       long   *fps;
  1605.       long   *pframes;
  1606.       long   *nopframes;
  1607.       long   *bframes;
  1608.       long   *nobframes;
  1609.       STRPTR  sample;
  1610.       long   *volume;
  1611.       long   *buflength;
  1612.       long   *loadall;
  1613.       long   *noloadall;
  1614.       long   *usevmm;
  1615.       long   *nousevmm;
  1616.       long   *mintotalmem;
  1617.       long   *ignoreerrors;
  1618.       long   *verbose;
  1619.       long   *progressgauge;
  1620.       long   *noprogressgauge;
  1621.       long   *quality;
  1622.       long   *noquality;
  1623.     } animargs;
  1624.  
  1625.     TEXT   varbuff[ 258 ];
  1626.     STRPTR var;
  1627.  
  1628.     if( var = GetPrefsVar( classbase, "Classes/DataTypes/mpegvideo.prefs" ) )
  1629.     {
  1630.       STRPTR prefsline      = var,
  1631.              nextprefsline;
  1632.       ULONG  linecount      = 1UL;
  1633.  
  1634.       /* Be sure that "var" contains at least one break-char */
  1635.       strcat( var, "\n" );
  1636.  
  1637.       while( nextprefsline = strpbrk( prefsline, "\n" ) )
  1638.       {
  1639.         stccpy( varbuff, prefsline, (int)MIN( (sizeof( varbuff ) - 2UL), (((ULONG)(nextprefsline - prefsline)) + 1UL) ) );
  1640.  
  1641.         /* be sure that this line isn't a comment line or an empty line */
  1642.         if( (varbuff[ 0 ] != '#') && (varbuff[ 0 ] != ';') && (varbuff[ 0 ] != '\n') && (strlen( varbuff ) > 2UL) )
  1643.         {
  1644.           /* Prepare ReadArgs processing */
  1645.           strcat( varbuff, "\n" );                                       /* Add NEWLINE-char            */
  1646.           envvarrda . RDA_Source . CS_Buffer = varbuff;                  /* Buffer                      */
  1647.           envvarrda . RDA_Source . CS_Length = strlen( varbuff ) + 1UL;  /* Set up input buffer length  */
  1648.           envvarrda . RDA_Source . CS_CurChr = 0L;
  1649.           envvarrda . RDA_Buffer = NULL;
  1650.           envvarrda . RDA_BufSiz = 0L;
  1651.           memset( (void *)(&animargs), 0, sizeof( animargs ) );          /* Clear result array          */
  1652.  
  1653.           if( ReadArgs( "MATCHPROJECT/K,"
  1654.                         "MODEID/K/N,"
  1655.                         "WIDTH/K/N,"
  1656.                         "HEIGHT/K/N,"
  1657.                         "DEPTH/K/N,"
  1658.                         "DITHER/K,"
  1659.                         "LUM_RANGE/K/N,"
  1660.                         "CR_RANGE/K/N,"
  1661.                         "CB_RANGE/K/N,"
  1662.                         "COLORERROR/K/N,"
  1663.                         "PALETTEPERFRAME/S,"
  1664.                         "NOPALETTEPERFRAME/S,"
  1665.                         "GAMMACORRECT/K,"
  1666.                         "CHROMACORRECT/K,"
  1667.                         "MAXFRAME/K/N,"
  1668.                         "SKIPFRAMES/K/N,"
  1669.                         "FPS/K/N,"
  1670.                         "PFRAMES/S,"
  1671.                         "NOPFRAMES/S,"
  1672.                         "BFRAMES/S,"
  1673.                         "NOBFRAMES/S,"
  1674.                         "SAMPLE/K,"
  1675.                         "VOLUME/K/N,"
  1676.                         "BUFFER/K/N,"
  1677.                         "LOADALL/S,"
  1678.                         "NOLOADALL/S,"
  1679.                         "USEVMM/S,"
  1680.                         "NOUSEVMM/S,"
  1681.                         "MINTOTALMEM/K/N,"
  1682.                         "IGNOREERRORS/S,"
  1683.                         "VERBOSE/S,"
  1684.                         "PROGRESSGAUGE/S,"
  1685.                         "NOPROGRESSGAUGE/S,"
  1686.                         "QUALITY/S,"
  1687.                         "NOQUALITY/S", (LONG *)(&animargs), (&envvarrda) ) )
  1688.           {
  1689.             BOOL noignore = TRUE;
  1690.  
  1691.             if( (animargs . matchproject) && (mvid -> mvid_ProjectName) )
  1692.             {
  1693.               noignore = matchstr( classbase, (animargs . matchproject), (mvid -> mvid_ProjectName) );
  1694.             }
  1695.  
  1696.             if( noignore )
  1697.             {
  1698.               if( animargs . verbose )
  1699.               {
  1700.                 OpenLogfile( classbase, mvid );
  1701.               }
  1702.  
  1703.               if( animargs . modeid )
  1704.               {
  1705.                 mvid -> mvid_ModeID = *(animargs . modeid);
  1706.               }
  1707.  
  1708.               if( animargs . width )
  1709.               {
  1710.                 anim_width = *(animargs . width);
  1711.               }
  1712.  
  1713.               if( animargs . height )
  1714.               {
  1715.                 anim_height = *(animargs . height);
  1716.               }
  1717.  
  1718.               if( animargs . depth )
  1719.               {
  1720.                 anim_depth = *(animargs . depth);
  1721.  
  1722.                 /* check bounds */
  1723.                 if( anim_depth < 1UL )
  1724.                 {
  1725.                   anim_depth = 1UL;
  1726.                 }
  1727.  
  1728.                 if( anim_depth > 8UL )
  1729.                 {
  1730.                   anim_depth = 8UL;
  1731.                 }
  1732.               }
  1733.  
  1734.               if( animargs . dither )
  1735.               {
  1736.                 LONG d;
  1737.  
  1738.                 d = FindArg( "GRAY/S,"
  1739.                              "HAM/S,"
  1740.                              "COLOR/S,"
  1741.                              "HYBRID/S,"
  1742.                              "FS2/S,"
  1743.                              "FS4/S,"
  1744.                              "ORDERED/S,"
  1745.                              "24BITCHUNKY/S,"
  1746.                              "16BITCHUNKY/S,"
  1747.                              "24BITPLANAR/S", (animargs . dither) );
  1748.  
  1749.                 switch( d )
  1750.                 {
  1751.                   case 1: /* HAM */
  1752.                   {
  1753.                       ditherType          = HAM_DITHER;
  1754.                   }
  1755.                       break;
  1756.  
  1757. #if 0
  1758.                   case 2: /* COLOR */
  1759.                   {
  1760.                       ditherType = FAST_COLOR_DITHER;
  1761.                   }
  1762.                       break;
  1763. #endif
  1764.  
  1765.                   case 6:
  1766.                       ditherType = ORDERED_DITHER;
  1767.                       break;
  1768.  
  1769.                   case 7:
  1770.                   {
  1771.                       /* Check if we have animation.datatype V41 (or higher) as superclass */
  1772.                       if( ISV41 )
  1773.                       {
  1774.                         /* Check here if we opened the cybergraphics.library. After this point, I'll assume
  1775.                          * that (mvid_UseChunkyMap == TRUE) implies a opened CyberGfxBase !!
  1776.                          */
  1777.                         if( CyberGfxBase )
  1778.                         {
  1779.                           ditherType = FULL_COLOR_DITHER;
  1780.                           pixfmt = PIXFMT_ARGB32;
  1781.                           mvid -> mvid_UseChunkyMap = TRUE;
  1782.                         }
  1783.                         else
  1784.                         {
  1785.                           error_printf( mvid, "no cybergraphics.library available, can't output a 24 bit chunky map\n" );
  1786.                         }
  1787.                       }
  1788.                       else
  1789.                       {
  1790.                         error_printf( mvid, "Requires at least animation.datatype V41 for non-planar bitmap support\n" );
  1791.                       }
  1792.                   }
  1793.                       break;
  1794.  
  1795.                   case 8:
  1796.                   {
  1797.                       /* Check if we have animation.datatype V41 (or higher) as superclass */
  1798.                       if( ISV41 )
  1799.                       {
  1800.                         /* Check here if we opened the cybergraphics.library. After this point, I'll assume
  1801.                          * that (mvid_UseChunkyMap == TRUE) implies a opened CyberGfxBase !!
  1802.                          */
  1803.                         if( CyberGfxBase )
  1804.                         {
  1805.                           ditherType = FULL_COLOR_DITHER16;
  1806.                           pixfmt = PIXFMT_RGB16;
  1807.                           mvid -> mvid_UseChunkyMap = TRUE;
  1808.                         }
  1809.                         else
  1810.                         {
  1811.                           error_printf( mvid, "no cybergraphics.library available, can't output a 16 bit chunky map\n" );
  1812.                         }
  1813.                       }
  1814.                       else
  1815.                       {
  1816.                         error_printf( mvid, "Requires at least animation.datatype V41 for non-planar bitmap support\n" );
  1817.                       }
  1818.                   }
  1819.                       break;
  1820.  
  1821.                   case 9:
  1822.                   {
  1823.                       /* Check if we have animation.datatype V41 (or higher) as superclass */
  1824.                       if( ISV41 )
  1825.                       {
  1826.                         ditherType = FULL_COLOR_DITHER;
  1827.                         mvid -> mvid_UseChunkyMap = FALSE;
  1828.                       }
  1829.                       else
  1830.                       {
  1831.                         error_printf( mvid, "Requires at least animation.datatype V41 for 24 bit planar bitmap support\n" );
  1832.                       }
  1833.                   }
  1834.                       break;
  1835.  
  1836.                   case 0:
  1837.                   default:
  1838.                       ditherType = GRAY_DITHER;
  1839.                       break;
  1840.  
  1841.                 }
  1842.               }
  1843.  
  1844.               if( animargs . lum_range )
  1845.               {
  1846.                 LUM_RANGE = *(animargs . lum_range);
  1847.  
  1848.                 if( LUM_RANGE < 1UL ) LUM_RANGE = 1UL;
  1849.               }
  1850.  
  1851.               if( animargs . cr_range )
  1852.               {
  1853.                 CR_RANGE = *(animargs . cr_range);
  1854.  
  1855.                 if( CR_RANGE < 1UL ) CR_RANGE = 1UL;
  1856.               }
  1857.  
  1858.               if( animargs . cb_range )
  1859.               {
  1860.                 CB_RANGE = *(animargs . cb_range);
  1861.  
  1862.                 if( CB_RANGE < 1UL ) CB_RANGE = 1UL;
  1863.               }
  1864.  
  1865.               if( animargs . colorerror )
  1866.               {
  1867.                 mvid -> mvid_ColorError = *(animargs . colorerror);
  1868.               }
  1869.  
  1870.               if( animargs . paletteperframe )
  1871.               {
  1872.                 mvid -> mvid_PalettePerFrame = TRUE;
  1873.               }
  1874.  
  1875.               if( animargs . nopaletteperframe )
  1876.               {
  1877.                 mvid -> mvid_PalettePerFrame = FALSE;
  1878.               }
  1879.               
  1880.               if( animargs . gammacorrect )
  1881.               {
  1882.                 mvid -> mvid_gammaCorrect = strtod( (animargs . gammacorrect), NULL );
  1883.  
  1884.                 if( (mvid -> mvid_gammaCorrect) == 0.0 )
  1885.                 {
  1886.                   error_printf( mvid, "Illegal gamma correction value %s, restored to 1.0\n", (animargs . gammacorrect) );
  1887.  
  1888.                   mvid -> mvid_gammaCorrect = 1.0;
  1889.                 }
  1890.               }
  1891.  
  1892.               if( animargs . chromacorrect )
  1893.               {
  1894.                 mvid -> mvid_chromaCorrect = strtod( (animargs . chromacorrect), NULL );
  1895.  
  1896.                 if( (mvid -> mvid_chromaCorrect) == 0.0 )
  1897.                 {
  1898.                   error_printf( mvid, "Illegal chroma correction value %s, restored to 1.0\n", (animargs . chromacorrect) );
  1899.  
  1900.                   mvid -> mvid_chromaCorrect = 1.0;
  1901.                 }
  1902.               }
  1903.  
  1904.               if( animargs . maxframe )
  1905.               {
  1906.                 mvid -> mvid_MaxFrame = *(animargs . maxframe);
  1907.               }
  1908.  
  1909.               if( animargs . skipframes )
  1910.               {
  1911.                 mvid -> mvid_SkipFrames = *(animargs . skipframes);
  1912.               }
  1913.  
  1914.               if( animargs . fps )
  1915.               {
  1916.                 mvid -> mvid_TicksPerFrame = TICK_FREQ / MAX( (*(animargs . fps)), 1L );
  1917.               }
  1918.  
  1919.               if( animargs . pframes )
  1920.               {
  1921.                 mvid -> No_P_Flag = FALSE;
  1922.               }
  1923.  
  1924.               if( animargs . nopframes )
  1925.               {
  1926.                 mvid -> No_P_Flag = TRUE;
  1927.               }
  1928.  
  1929.               if( animargs . bframes )
  1930.               {
  1931.                 mvid -> No_B_Flag = FALSE;
  1932.               }
  1933.  
  1934.               if( animargs . nobframes )
  1935.               {
  1936.                 mvid -> No_B_Flag = TRUE;
  1937.               }
  1938.  
  1939.               if( (animargs . sample) && ((mvid -> mvid_Sample) == NULL) )
  1940.               {
  1941.                 Object *so;
  1942.                 LONG    ioerr = 0L;
  1943.  
  1944.                 verbose_printf( mvid, "loading sample \"%s\"...\n", (animargs . sample) );
  1945.  
  1946.                 if( so = NewDTObject( (animargs . sample), DTA_GroupID, GID_SOUND, TAG_DONE ) )
  1947.                 {
  1948.                   BYTE *sample;
  1949.                   ULONG length;
  1950.                   ULONG period;
  1951.  
  1952.                   /* Get sample data from object */
  1953.                   if( GetDTAttrs( so, SDTA_Sample,       (&sample),
  1954.                                       SDTA_SampleLength, (&length),
  1955.                                       SDTA_Period,       (&period),
  1956.                                       TAG_DONE ) == 3UL )
  1957.                   {
  1958.                     if( mvid -> mvid_Sample = (STRPTR)AllocPooled( (mvid -> mvid_Pool), (length + 1UL) ) )
  1959.                     {
  1960.                       /* Copy sample and context */
  1961.                       CopyMem( (APTR)sample, (APTR)(mvid -> mvid_Sample), length );
  1962.                       mvid -> mvid_SampleLength = length;
  1963.                       mvid -> mvid_Period       = period;
  1964.                     }
  1965.                     else
  1966.                     {
  1967.                       /* Can't alloc sample */
  1968.                       ioerr = ERROR_NO_FREE_STORE;
  1969.                     }
  1970.                   }
  1971.                   else
  1972.                   {
  1973.                     /* Object does not support the requested attributes */
  1974.                     ioerr = ERROR_OBJECT_WRONG_TYPE;
  1975.                   }
  1976.  
  1977.                   DisposeDTObject( so );
  1978.                 }
  1979.                 else
  1980.                 {
  1981.                   ioerr = IoErr();
  1982.                 }
  1983.  
  1984.                 if( (mvid -> mvid_Sample) == NULL )
  1985.                 {
  1986.                   TEXT errbuff[ 256 ];
  1987.  
  1988.                   if( ioerr >= DTERROR_UNKNOWN_DATATYPE )
  1989.                   {
  1990.                     mysprintf( classbase, errbuff, GetDTString( ioerr ), (animargs . sample) );
  1991.                   }
  1992.                   else
  1993.                   {
  1994.                     Fault( ioerr, (animargs . sample), errbuff, sizeof( errbuff ) );
  1995.                   }
  1996.  
  1997.                   error_printf( mvid, "can't load sample: \"%s\" line %lu\n", errbuff, linecount );
  1998.                 }
  1999.               }
  2000.  
  2001.               if( animargs . volume )
  2002.               {
  2003.                 mvid -> mvid_Volume = *(animargs . volume);
  2004.  
  2005.                 if( (mvid -> mvid_Volume) > 64UL )
  2006.                 {
  2007.                   mvid -> mvid_Volume = 64UL;
  2008.                 }
  2009.               }
  2010.               else
  2011.               {
  2012.                 mvid -> mvid_Volume = 64UL;
  2013.               }
  2014.  
  2015.               if( animargs . buflength )
  2016.               {
  2017.                 mvid -> mvid_BufLength = *(animargs . buflength);
  2018.  
  2019.                 if( (mvid -> mvid_BufLength) < 2048UL )
  2020.                 {
  2021.                   mvid -> mvid_BufLength = 2048UL;
  2022.                 }
  2023.               }
  2024.  
  2025.               if( animargs . loadall )
  2026.               {
  2027.                 mvid -> mvid_LoadAll = TRUE;
  2028.               }
  2029.  
  2030.               if( animargs . noloadall )
  2031.               {
  2032.                 mvid -> mvid_LoadAll = FALSE;
  2033.               }
  2034.  
  2035.               if( animargs . usevmm )
  2036.               {
  2037.                 /* vmm.library useable ? */
  2038.                 mvid -> mvid_UseVMM = AttemptOpenVMM( mvid );
  2039.               }
  2040.  
  2041.               if( animargs . nousevmm )
  2042.               {
  2043.                 mvid -> mvid_UseVMM = FALSE;
  2044.               }
  2045.  
  2046.               if( animargs . mintotalmem )
  2047.               {
  2048.                 mvid -> mvid_MinTotalMem = *(animargs . mintotalmem);
  2049.               }
  2050.  
  2051.               if( animargs . ignoreerrors )
  2052.               {
  2053.                 mvid -> mvid_IgnoreErrors = TRUE;
  2054.               }
  2055.  
  2056.               if( animargs . progressgauge )
  2057.               {
  2058.                 mvid -> mvid_PR . pr_Max = 0UL;
  2059.               }
  2060.  
  2061.               if( animargs . noprogressgauge )
  2062.               {
  2063.                 mvid -> mvid_PR . pr_Max = ~0UL;
  2064.               }
  2065.  
  2066.               if( animargs . quality )
  2067.               {
  2068.                 mvid -> mvid_Quality = TRUE;
  2069.               }
  2070.  
  2071.               if( animargs . noquality )
  2072.               {
  2073.                 mvid -> mvid_Quality = FALSE;
  2074.               }
  2075.             }
  2076.             else
  2077.             {
  2078.               verbose_printf( mvid, "prefs line %lu ignored\n", linecount );
  2079.             }
  2080.  
  2081.             FreeArgs( (&envvarrda) );
  2082.           }
  2083.           else
  2084.           {
  2085.             LONG ioerr = IoErr();
  2086.             TEXT errbuff[ 256 ];
  2087.  
  2088.             OpenLogfile( classbase, mvid );
  2089.  
  2090.             Fault( ioerr, "Classes/DataTypes/mpegvideo.prefs", errbuff, sizeof( errbuff ) );
  2091.  
  2092.             error_printf( mvid, "preferences \"%s\" line %lu\n", errbuff, linecount );
  2093.           }
  2094.         }
  2095.  
  2096.         prefsline = ++nextprefsline;
  2097.         linecount++;
  2098.       }
  2099.  
  2100.       FreeVec( var );
  2101.     }
  2102. }
  2103.  
  2104.  
  2105. static
  2106. void AttachSample( struct MPEGVideoInstData *mvid )
  2107. {
  2108.     struct ClassBase *classbase = mvid -> mvid_ClassBase;
  2109.  
  2110.     if( mvid -> mvid_Sample )
  2111.     {
  2112.       struct FrameNode *worknode,
  2113.                        *nextnode;
  2114.  
  2115.       ULONG             period          = ((mvid -> mvid_Period) * (TICK_FREQ / xtpf)) / (TICK_FREQ / (mvid -> mvid_TicksPerFrame));
  2116.       ULONG             samplesperframe = (((SysBase -> ex_EClockFrequency) * 10UL) / (period * (TICK_FREQ / (mvid -> mvid_TicksPerFrame)) * 2UL));
  2117.       BYTE             *sample          = mvid -> mvid_Sample;
  2118.  
  2119.       verbose_printf( mvid, "Attching samples (sysclock %lu period %lu fps %lu length %lu samplesperframe %lu)...\n",
  2120.                       (SysBase -> ex_EClockFrequency), period, (TICK_FREQ / (mvid -> mvid_TicksPerFrame)), (mvid -> mvid_SampleLength), samplesperframe );
  2121.  
  2122.       worknode = (struct FrameNode *)(mvid -> mvid_FrameList . mlh_Head);
  2123.  
  2124.       while( nextnode = (struct FrameNode *)(worknode -> fn_Node . mln_Succ) )
  2125.       {
  2126.         worknode -> fn_Sample       = sample;
  2127.         worknode -> fn_SampleLength = samplesperframe * ((worknode -> fn_Duration) + 1UL);
  2128.         worknode -> fn_Period       = period;
  2129.  
  2130.         sample += worknode -> fn_SampleLength;
  2131.  
  2132.         /* End of sample reached ? */
  2133.         if( (ULONG)(sample - (mvid -> mvid_Sample)) > (mvid -> mvid_SampleLength) )
  2134.         {
  2135.           /* Cut last size of sample to fit */
  2136.           worknode -> fn_SampleLength -= (ULONG)(sample - (mvid -> mvid_Sample));
  2137.  
  2138.           break;
  2139.         }
  2140.  
  2141.         worknode = nextnode;
  2142.       }
  2143.     }
  2144. }
  2145.  
  2146.  
  2147. static
  2148. BOOL AttemptOpenVMM( struct MPEGVideoInstData *mvid )
  2149. {
  2150.     struct ClassBase *classbase = mvid -> mvid_ClassBase;
  2151.  
  2152.     ObtainSemaphore( (&(classbase -> cb_Lock)) );
  2153.  
  2154.     if( (classbase -> cb_VMMBase) == NULL )
  2155.     {
  2156.       /* vmm.library will be closed in LibExpunge */
  2157.       classbase -> cb_VMMBase = OpenLibrary( "vmm.library", 3UL );
  2158.     }
  2159.  
  2160.     /* vmm.library loaded ? */
  2161.     if( classbase -> cb_VMMBase )
  2162.     {
  2163.       verbose_printf( mvid, "*** using \"vmm.library\" virtual memory\n" );
  2164.     }
  2165.     else
  2166.     {
  2167.       error_printf( mvid, "*** \"vmm.library\" version 3 not found\n" );
  2168.     }
  2169.  
  2170.     ReleaseSemaphore( (&(classbase -> cb_Lock)) );
  2171.  
  2172.     return( MAKEBOOL( (classbase -> cb_VMMBase) ) );
  2173. }
  2174.  
  2175.  
  2176. static
  2177. void OpenLogfile( struct ClassBase *classbase, struct MPEGVideoInstData *mvid )
  2178. {
  2179.     if( (mvid -> mvid_VerboseOutput) == NULL )
  2180.     {
  2181.       STRPTR confile;
  2182.  
  2183.       if( confile = (STRPTR)AllocVec( (((mvid -> mvid_ProjectName)?(strlen( (mvid -> mvid_ProjectName) )):(0UL)) + 100UL), MEMF_PUBLIC ) )
  2184.       {
  2185.         mysprintf( classbase, confile, "CON:////MPEG Video DataType %s/auto/wait/close/inactive",
  2186.                    ((mvid -> mvid_ProjectName)?(FilePart( (mvid -> mvid_ProjectName) )):(NULL)) );
  2187.  
  2188.         mvid -> mvid_VerboseOutput = Open( confile, MODE_READWRITE );
  2189.  
  2190.         FreeVec( confile );
  2191.       }
  2192.     }
  2193. }
  2194.  
  2195.  
  2196. static
  2197. void CreateProgressRequester( struct MPEGVideoInstData *mvid )
  2198. {
  2199.     struct ClassBase *classbase     = mvid -> mvid_ClassBase;
  2200.     struct Process   *ThisProcess   = (struct Process *)FindTask( NULL );
  2201.     struct Screen    *scr           = NULL,
  2202.                      *pubscr        = NULL;
  2203.  
  2204.     /* Check if progress gauge was disabled by prefs... */
  2205.     if( (mvid -> mvid_PR . pr_Max) != ~0UL )
  2206.     {
  2207.       /* Get progress requester's screen */
  2208.       if( ThisProcess -> pr_WindowPtr )
  2209.       {
  2210.         scr = ((struct Window *)(ThisProcess -> pr_WindowPtr)) -> WScreen;
  2211.       }
  2212.       else
  2213.       {
  2214.         pubscr = LockPubScreen( NULL );
  2215.       }
  2216.  
  2217.       /* Valid screen ? */
  2218.       if( scr || pubscr )
  2219.       {
  2220.         struct Screen   *s    = (scr)?(scr):(pubscr);
  2221.         struct TextFont *font = (s -> RastPort . Font)?(s -> RastPort . Font):(GfxBase -> DefaultFont);
  2222.  
  2223.         if( font )
  2224.         {
  2225.           ULONG width,
  2226.                 height;
  2227.  
  2228.           width  =  MAX( (font -> tf_XSize), 8 ) * 42UL;
  2229.           height = (MAX( (font -> tf_YSize), 8 ) * 5UL) / 3UL;
  2230.  
  2231.           if( mvid -> mvid_PR . pr_Window = OpenWindowTags( NULL, WA_InnerWidth,                    width,
  2232.                                                                   WA_InnerHeight,                   height,
  2233.                                                                   WA_MinWidth,                      (width / 2UL),
  2234.                                                                   WA_MinHeight,                     0UL, /* overtake value calculated by WA_InnerHeight */
  2235.                                                                   WA_MaxWidth,                      (~0UL),
  2236.                                                                   WA_MaxHeight,                     0UL, /* overtake value calculated by WA_InnerHeight */
  2237.                                                                   WA_SizeGadget,                    TRUE,
  2238.                                                                   WA_DragBar,                       TRUE,
  2239.                                                                   WA_DepthGadget,                   TRUE,
  2240.                                                                   WA_CloseGadget,                   TRUE,
  2241.                                                                   WA_RMBTrap,                       TRUE,
  2242.                                                                   WA_IDCMP,                         IDCMP_CLOSEWINDOW,
  2243.                                                                   WA_Title,                         (mvid -> mvid_ProjectName),
  2244.                                                                   WA_ScreenTitle,                   (mvid -> mvid_ProjectName),
  2245.                                                                   XTAG( scr,    WA_CustomScreen ),  scr,
  2246.                                                                   XTAG( pubscr, WA_PubScreen    ),  pubscr,
  2247.                                                                   TAG_DONE ) )
  2248.           {
  2249.             ULONG dummy;
  2250.  
  2251.             /* Snapshot start of decoding... */
  2252.             CurrentTime( (&(mvid -> mvid_PR . pr_StartSecond)), (&dummy) );
  2253.           }
  2254.         }
  2255.       }
  2256.  
  2257.       if( pubscr )
  2258.       {
  2259.         UnlockPubScreen( NULL, pubscr );
  2260.       }
  2261.     }
  2262. }
  2263.  
  2264.  
  2265. void UpdateProgressRequester( struct MPEGVideoInstData *mvid )
  2266. {
  2267.     struct ClassBase *classbase = mvid -> mvid_ClassBase;
  2268.     struct Window    *win;
  2269.  
  2270.     if( (mvid -> mvid_PR . pr_Max) == 0UL )
  2271.     {
  2272.       mvid -> mvid_PR . pr_Max = 1UL;
  2273.     }
  2274.  
  2275.     if( win = mvid -> mvid_PR . pr_Window )
  2276.     {
  2277.       ULONG                 left      = (win -> BorderLeft) + 1UL,
  2278.                             top       = (win -> BorderTop)  + 1UL,
  2279.                             width     = (win -> Width)  - (win -> BorderLeft) - (win -> BorderRight)  - 3UL,
  2280.                             height    = (win -> Height) - (win -> BorderTop)  - (win -> BorderBottom) - 3UL,
  2281.                             currwidth = (ULONG)((double)width * ((double)(mvid -> mvid_PR . pr_Curr) / (double)(mvid -> mvid_PR . pr_Max)));
  2282.       struct IntuiMessage  *imsg;
  2283.  
  2284.       /* Check bounds... */
  2285.       if( currwidth > width )
  2286.       {
  2287.         currwidth = width;
  2288.       }
  2289.  
  2290.       /* Draw gauge part representing the loaded frames... */
  2291.       SetAPen( (win -> RPort), (ULONG)(win -> BlockPen) );
  2292.       RectFill( (win -> RPort), left, top, (left + currwidth), (top + height) );
  2293.  
  2294.       /* ...then draw gauge part representing remaining bytes in the stream */
  2295.       SetAPen( (win -> RPort), (ULONG)(win -> DetailPen) );
  2296.       RectFill( (win -> RPort), (left + currwidth), top, (left + width), (top + height) );
  2297.  
  2298.       /* Render the time (max and current) */
  2299.       {
  2300.         TEXT  buffer[ 256 ];
  2301.         ULONG currsec,
  2302.               currmic,
  2303.               fullsec;
  2304.         ULONG textlen,
  2305.               x;
  2306.  
  2307.         /* Current time */
  2308.         CurrentTime( (&currsec), (&currmic) );
  2309.         currsec = currsec - (mvid -> mvid_PR . pr_StartSecond);
  2310.  
  2311.         /* Full decoding time */
  2312.         fullsec = (ULONG)((double)currsec / (double)(mvid -> mvid_PR . pr_Curr) * (double)(mvid -> mvid_PR . pr_Max));
  2313.  
  2314.         /* Write buffer */
  2315.         mysprintf( classbase, buffer, "%lu:%02.2lu/%lu:%02.2lu",
  2316.                    (currsec / 60UL), (currsec % 60UL),
  2317.                    (fullsec / 60UL), (fullsec % 60UL) );
  2318.  
  2319.         textlen = TextLength( (win -> RPort), buffer, (ULONG)strlen( buffer ) );
  2320.  
  2321.         x = ((width - textlen) / 2UL) + 1UL;
  2322.  
  2323.         /* Print "remaining seconds text" */
  2324.         SetDrMd( (win -> RPort), (JAM1 | COMPLEMENT) );
  2325.         Move( (win -> RPort), x, (top + (win -> RPort -> Font -> tf_Baseline) + 2UL) );
  2326.  
  2327.         Text( (win -> RPort), buffer, (ULONG)strlen( buffer ) );
  2328.  
  2329.         SetDrMd( (win -> RPort), JAM1 );
  2330.       }
  2331.  
  2332.       /* Check for the close gadget */
  2333.       while( imsg = (struct IntuiMessage *)GetMsg( (win -> UserPort) ) )
  2334.       {
  2335.         /* Handle each message */
  2336.         switch( imsg -> Class )
  2337.         {
  2338.           case IDCMP_CLOSEWINDOW:
  2339.           {
  2340.               /* Set abort signal... */
  2341.               Signal( FindTask( NULL ), SIGBREAKF_CTRL_D );
  2342.           }
  2343.               break;
  2344.         }
  2345.  
  2346.         ReplyMsg( (&(imsg -> ExecMessage)) );
  2347.       }
  2348.     }
  2349. }
  2350.  
  2351.  
  2352. static
  2353. void DeleteProgressRequester( struct MPEGVideoInstData *mvid )
  2354. {
  2355.     struct ClassBase *classbase = mvid -> mvid_ClassBase;
  2356.  
  2357.     if( mvid -> mvid_PR . pr_Window )
  2358.     {
  2359.       CloseWindow( (mvid -> mvid_PR . pr_Window) );
  2360.       mvid -> mvid_PR . pr_Window = NULL;
  2361.     }
  2362. }
  2363.  
  2364.  
  2365.  
  2366.